package com.lecture.junit.tdd.example;

import java.util.Calendar;
import java.util.Date;

/**
 * User: Yury
 */
public abstract class LoginServiceState {

    private static final int PASSWORD_EXPIRED_DAYS = 30;
    private static final int ACCOUNT_REVOKED_DAYS = 45;

    public void login(IAccount acc, String password, LoginService context) throws AccountNotFoundException,
            AccountAlreadyRevokedException, PasswordExpiredException {

        if (acc.passwordMatches(password)) {
            if (acc.isRevoked()) {
                throw new AccountAlreadyRevokedException("Account is already revoked");
            }
            assureAccountUsedRecently(acc);
            assurePasswordChangedRecently(acc);
            acc.setLoggedIn(true);
            acc.setLastLoginTime(new Date());
            context.setState(acc.getUserName(), new FirstFailedAttempt());
        } else {
            dealWithFailedAttempt(acc, context);
        }
    }

    protected abstract void dealWithFailedAttempt(IAccount acc, LoginService context);

    private void assureAccountUsedRecently(IAccount acc) throws AccountAlreadyRevokedException {
        Date date = acc.getLastUsedDate() ;
        if (date == null){
            return;
        }
        if (getRequiredLastAccessDate().after(date)){
            acc.setRevoked(true);
            throw new AccountAlreadyRevokedException("Account was revoked.");
        }
    }

    private void assurePasswordChangedRecently(IAccount acc) throws PasswordExpiredException {
        if (acc.getPasswordChangedDate() == null){
            return;
        }
        if (getRequiredPasswordChangeDate().after(acc.getPasswordChangedDate())){
            throw new PasswordExpiredException("Password expired.");
        }
    }

    private Date getRequiredPasswordChangeDate(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -PASSWORD_EXPIRED_DAYS);
        return calendar.getTime();
    }

    private Date getRequiredLastAccessDate(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -ACCOUNT_REVOKED_DAYS);
        return calendar.getTime();
    }

    public static int getPasswordExpiredDays() {
        return PASSWORD_EXPIRED_DAYS;
    }

    public static int getAccountRevokedDays() {
        return ACCOUNT_REVOKED_DAYS;
    }
}
